<script lang="ts" setup>
import { type PropType, ref, watch } from 'vue'
import { wait } from '@/utils/utils'

const props = defineProps({
    list: {
        type: Array satisfies PropType<AnyObject[]>,
        default: () => [],
    },
    column: {
        type: Number,
        default: 2,
    },
})

const renderList = ref()

const hasData = ref(false)

/**
 * 根据需要渲染的列数，创建需要渲染的列表数，比如需要渲染两列，那么就初始化一个长度为2的二维数组[[], []]
 */
watch(() => props.column, (res) => {
    renderList.value = Array.from({ length: props.column }, () => [])
}, {
    immediate: true,
})

/**
 * 通过计算每个列表的高度，找到最小高度对应的索引值，然后将数据插入到该索引对应的列表中
 * @param list 渲染的列表
 * @param reset 是否要重置，比如下拉刷新的时候
 */
function render(list: AnyObject[], reset: boolean) {
    hasData.value = list.length > 0
    if (reset)
        renderList.value = Array.from({ length: props.column }, () => [])
    if (!list?.length)
        return

    list.forEach(async (item, index) => {
        await wait(50 * index)
        const minHeightIndex = await getMinHeightIndex()
        if (renderList.value[minHeightIndex].every((i: AnyObject) => i.id !== item.id))
            renderList.value[minHeightIndex].push(item)
    })
}

/**
 * 计算每个列表的高度，找到最小高度对应的索引值
 */
async function getMinHeightIndex() {
    return new Promise<number>(async (resolve) => {
        const heightInfo = await createHeightInfo()
        const res = heightInfo.reduce((prev, next) => {
            return heightInfo.findIndex(i => i === Math.min(prev, next))
        })
        resolve(res)
    })
}

/**
 * 创建所有列表的高度信息以方便找到高度最小的一项
 */
async function createHeightInfo() {
    return new Promise<number[]>(async (resolve) => {
        const heightInfo: number[] = []
        const asyncList = [] as Promise<Awaited<ReturnType<typeof getDomHeight>>>[]
        renderList.value?.forEach(async (item: AnyObject, index: number) => {
            asyncList.push(getDomHeight(`water_${index}`))
        })
        const resList = await Promise.all(asyncList)
        resList.forEach((item, index) => {
            heightInfo[index] = item
        })
        resolve(heightInfo)
    })
}

/**
 * 根据id获取dom高度信息
 * @param id
 */
function getDomHeight(id: string) {
    return new Promise<number>((resolve) => {
        const query = uni.createSelectorQuery()
        query
            .select(`#${id}`)
            .boundingClientRect()
            .exec((res) => {
                resolve(res[0].height)
            })
    })
}

defineExpose({ render })
</script>

<template>
    <view>
        <view class="w-full overflow-auto">
            <view v-for="(item, index) in renderList" :id="`water_${index}`" :key="index"
                  :class="{ 'mr-40rpx': index === 0 }" class="float-left"
                  :style="{ width: `calc(100%/${props.column} - 22rpx)` }">
                <view v-for="(data, idx) in item" :key="idx">
                    <slot name="default" :item-data="data" />
                </view>
            </view>
        </view>
        <view v-show="!hasData">
            <slot name="empty" />
        </view>
    </view>
</template>

<style lang="scss" scoped></style>
